#include <ESP8266WiFi.h>
//任意引脚串口通信
#include <SoftwareSerial.h>
SoftwareSerial mySerial(4, 5);  // 定义软件串口对象，IO4为RX引脚，IO5为TX引脚

//ws2812
#include <Adafruit_NeoPixel.h>
#define PIN 14         // 定义Neopixel数据引脚
#define NUMPIXELS 60   // 定义LED灯珠数量
#define BRIGHTNESS 30  // 设置亮度值 (0-255)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

//红外信号
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

const uint16_t kIrLed = 13;  //发射引脚
IRsend irsend(kIrLed);       // Set the GPIO to be used to sending the message.

//开风扇
uint16_t rawData1[143] = { 1286, 426, 1258, 426, 440, 1220, 1284, 426, 1282, 402, 440, 1242, 442, 1220, 464, 1216, 468, 1242, 442, 1244, 1260, 426, 440, 7952, 1314, 400, 1284, 400, 440, 1244, 1282, 402, 1264, 420, 440, 1244, 440, 1244, 440, 1218, 468, 1240, 442, 1214, 1310, 402, 438, 7956, 1310, 402, 1282, 404, 440, 1216, 1310, 402, 1280, 404, 440, 1212, 470, 1216, 468, 1214, 470, 1216, 468, 1214, 1312, 402, 440, 7954, 1312, 374, 1310, 372, 468, 1214, 1312, 372, 1312, 372, 470, 1214, 470, 1214, 470, 1214, 470, 1214, 470, 1214, 1310, 372, 468, 7956, 1308, 374, 1310, 374, 434, 1250, 1310, 374, 1308, 376, 436, 1248, 470, 1212, 470, 1214, 468, 1216, 472, 1212, 1314, 370, 472, 7952, 1310, 374, 1308, 376, 466, 1216, 1284, 402, 1306, 376, 466, 1218, 466, 1218, 464, 1220, 464, 1222, 436, 1246, 1280, 404, 438 };

//关风扇
uint16_t rawData2[47] = { 1274, 408, 1278, 406, 436, 1270, 1252, 410, 1280, 404, 464, 1240, 410, 1274, 410, 1274, 410, 1274, 408, 1274, 410, 1274, 410, 7994, 1274, 408, 1304, 380, 464, 1242, 1252, 412, 1310, 374, 468, 1236, 412, 1274, 408, 1276, 410, 1274, 408, 1274, 410, 1252, 432 };  // SYMPHONY D80

//兑
int array1[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
//离
int array2[8] = { 9, 10, 11, 12, 13, 14, 15, 16 };
//震
int array3[7] = { 17, 18, 19, 20, 21, 22, 23 };
//坤
int array4[6] = { 24, 25, 26, 27, 28, 29 };
//艮
int array5[7] = { 30, 31, 32, 33, 34, 35, 36 };
//坎
int array6[7] = { 37, 38, 39, 40, 41, 42, 43 };
//巽
int array7[8] = { 44, 45, 46, 47, 48, 49, 50, 51 };
//乾
int array8[9] = { 52, 53, 54, 55, 56, 57, 58, 59, 60 };

//内一圈
int array9[20] = { 1, 2, 3, 9, 10, 11, 17, 18, 19, 24, 25, 30, 31, 37, 38, 44, 45, 52, 53, 54 };
//内二圈
int array10[20] = { 4, 5, 6, 12, 13, 20, 21, 26, 27, 32, 33, 39, 40, 41, 46, 47, 48, 55, 56, 57 };
//内三圈
int array11[20] = { 7, 8, 14, 15, 16, 22, 23, 28, 29, 34, 35, 36, 42, 43, 49, 50, 51, 58, 59, 60 };
//从内到外所有
int array12[60] = { 1, 2, 3, 9, 10, 11, 17, 18, 19, 24, 25, 30, 31, 37, 38, 44, 45, 52, 53, 54, 4, 5, 6, 12, 13, 20, 21, 26, 27, 32, 33, 39, 40, 41, 46, 47, 48, 55, 56, 57, 7, 8, 14, 15, 16, 22, 23, 28, 29, 34, 35, 36, 42, 43, 49, 50, 51, 58, 59, 60 };

// 定义颜色数组
uint32_t colors[8];

//颜色
uint32_t red = strip.Color(255, 0, 0);        // 红色
uint32_t green = strip.Color(0, 255, 0);      // 绿色
uint32_t blue = strip.Color(0, 0, 255);       // 蓝色
uint32_t yellow = strip.Color(255, 255, 0);   // 黄色
uint32_t magenta = strip.Color(255, 0, 255);  // 品红
uint32_t cyan = strip.Color(0, 255, 255);     // 青色
uint32_t white = strip.Color(255, 255, 255);  // 白色
uint32_t orange = strip.Color(255, 165, 0);   // 橙色

String flag = "close";  //流程控制
int speed = 350;        //旋转速度
int my_index = 1;       //最终选中卦象
int my_color = 0;       //颜色变化

// 函数: 填充颜色数组
void fillColorsArray() {
  // 将颜色值填入数组
  colors[0] = red;
  colors[1] = green;
  colors[2] = blue;
  colors[3] = yellow;
  colors[4] = magenta;
  colors[5] = cyan;
  colors[6] = white;
  colors[7] = orange;
}

//亮完后关闭,延时时间递减
void printArray(int arr[], int size, uint32_t color) {
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, color);
    strip.show();
  }
  delay(speed);
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, strip.Color(0, 0, 0));
    strip.show();
  }
}

//亮完后不关闭，逐卦点亮
void printArrayTwo(int arr[], int size, uint32_t color) {
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, color);
    strip.show();
  }
  delay(100);
}

//亮完后关闭,逐卦点亮
void printArrayThree(int arr[], int size, uint32_t color) {
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, color);
    strip.show();
  }
  delay(200);
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, strip.Color(0, 0, 0));
    strip.show();
  }
}

//亮完后熄灭,逐颗点亮
void printArrayFour(int arr[], int size, uint32_t color) {
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, color);
    strip.show();
    delay(50);
  }
  delay(50);
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, strip.Color(0, 0, 0));
    strip.show();
    delay(50);
  }
}

//亮一卦
void showOne(int arr[], int size, uint32_t color) {
  for (int j = 0; j < size; j++) {
    strip.setPixelColor(arr[j] - 1, color);
    strip.show();
  }
}

void showRandom() {
  int random_number = random(1, 9);  // 生成一个1到8之间的随机数，注意上界是排他性的，所以用101来包含100
  my_index = random_number;
  while (speed > 0) {  // 当speed大于于0时继续循环
    printArray(array8, 9, orange);
    printArray(array7, 8, white);
    printArray(array6, 7, cyan);
    printArray(array5, 7, magenta);
    printArray(array4, 6, yellow);
    printArray(array3, 7, blue);
    printArray(array2, 8, green);
    printArray(array1, 8, red);
    speed = speed - 100;
    if (speed < 0) {
      speed = 0;
    }
  }
  flag = "one";
}

void showOne() {
  switch (my_index) {
    case 1:
      showOne(array1, 8, red);
      break;
    case 2:
      showOne(array2, 8, green);
      break;
    case 3:
      showOne(array3, 7, blue);
      break;
    case 4:
      showOne(array4, 6, yellow);
      break;
    case 5:
      showOne(array5, 7, magenta);
      break;
    case 6:
      showOne(array6, 7, cyan);
      break;
    case 7:
      showOne(array7, 8, white);
      break;
    case 8:
      showOne(array8, 9, orange);
      break;
  }
}

// 关闭所有 LED
void showClose() {
  for (int i = 0; i < strip.numPixels(); i++) {  // 循环遍历每一个 LED
    strip.setPixelColor(i, 0, 0, 0);             // 设置颜色为黑色
  }
  strip.show();  // 更新 LED 显示
}

//卦象跑马灯
void showGuaHorse(uint32_t color) {
  printArrayTwo(array8, 9, color);
  printArrayTwo(array7, 8, color);
  printArrayTwo(array6, 7, color);
  printArrayTwo(array5, 7, color);
  printArrayTwo(array4, 6, color);
  printArrayTwo(array3, 7, color);
  printArrayTwo(array2, 8, color);
  printArrayTwo(array1, 8, color);
}

//从内向外扩散
void showKuoSan() {
  printArrayThree(array9, 20, red);
  printArrayThree(array10, 20, green);
  printArrayThree(array11, 20, blue);
}

// 从内开始依次点亮
void showFlow(uint32_t color) {
  printArrayFour(array12, 60, color);
}

// 一次打开所有灯珠
void showAll() {
  for (int i = 0; i < strip.numPixels(); i++) {  // 循环遍历每一个 LED
    strip.setPixelColor(i, white);               // 设置颜色为黑色
    strip.show();                                // 更新 LED 显示
    delay(30);
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);  // 启动串口通讯
  mySerial.begin(9600);  // 启动和语音芯片的串口通讯

  //设置ESP8266工作模式为无线终端模式
  // WiFi.mode(WIFI_STA);

  // 关闭Wi-Fi
  WiFi.mode(WIFI_OFF);

  fillColorsArray();  // 填充颜色数组

  strip.begin();
  strip.setBrightness(BRIGHTNESS);  // 设置亮度

  irsend.begin();  //开红外
}

void loop() {
  // put your main code here, to run repeatedly:
  doMySerial();

  if (flag == "close") {
    showClose();
  }

  if (flag == "random") {
    showRandom();
    speed = 350;
  }

  if (flag == "one") {
    showOne();
  }

  if (flag == "kuoSan") {
    showKuoSan();
  }

  if (flag == "guaHorse") {
    showGuaHorse(colors[my_color]);
    my_color++;
    if (my_color > 7) {
      my_color = 0;
    }
  }

  if (flag == "flow") {
    showFlow(colors[my_color]);
    my_color++;
    if (my_color > 7) {
      my_color = 0;
    }
  }

  if (flag == "all") {
    showAll();
  }

  if (flag == "openFan") {
    irsend.sendRaw(rawData1, 143, 38);  // Send a raw data capture at 38kHz.
    flag = "close";
  }

  if (flag == "closeFan") {
    irsend.sendRaw(rawData2, 47, 38);  // Send a raw data capture at 38kHz.
    flag = "close";
  }
}

void doMySerial() {
  // 接收串口数据
  // if (Serial.available()) {
  //   String receivedData = Serial.readString();
  //   Serial.print("Received data: ");
  //   Serial.println(receivedData);
  //   flag = receivedData;
  // }

  if (mySerial.available()) {
    String receivedData = mySerial.readString();
    Serial.print("Received data: ");
    Serial.println(receivedData);
    flag = receivedData;
  }
}
